using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using NUnit.Framework;

namespace Drill.LocatorPattern
{
    [TestFixture]
	public class LocatorExceptionTests
    {
        [Category("UnitTest")]
        [Test]
        public void CanConstructWithNoParameters()
        {
            LocatorException dependencyResolverException = new LocatorException();

            Assert.That(dependencyResolverException, Is.Not.Null);
        }

        [Category("UnitTest")]
        [Test]
        public void CanConstructWithMessageParameter()
        {
            const string message = "This is a test message.";

            LocatorException dependencyResolverException = new LocatorException(message);

            Assert.That(dependencyResolverException, Is.Not.Null);
            Assert.That(dependencyResolverException.Message, Is.EqualTo(message));
        }

        [Category("UnitTest")]
        [Test]
        public void CanConstructWithMessageAndInnerExceptionParameters()
        {
            const string message = "This is a test message.";

            Exception innerException = new Exception("This is an inner exception.");

            LocatorException dependencyResolverException = new LocatorException(message, innerException);

            Assert.That(dependencyResolverException, Is.Not.Null);
            Assert.That(dependencyResolverException.Message, Is.EqualTo(message));
            Assert.That(dependencyResolverException.InnerException, Is.EqualTo(innerException));
        }

        [Category("UnitTest")]
        [Test]
        public void CanConstructWithMessageAndArg0Parameters()
        {
            const string expectedFormattedMessage = "This is a formatted test message with arg0Value.";
            const string message = "This is a formatted test message with {0}.";
            const string arg0 = "arg0Value";

            LocatorException dependencyResolverException = new LocatorException(message, arg0);

            Assert.That(dependencyResolverException, Is.Not.Null);
            Assert.That(dependencyResolverException.Message, Is.EqualTo(expectedFormattedMessage));
        }

        [Category("UnitTest")]
        [Test]
        public void CanConstructWithMessageArg0AndArg1Parameters()
        {
            const string expectedFormattedMessage = "This is a formatted test message with arg0Value and arg1Value.";
            const string message = "This is a formatted test message with {0} and {1}.";
            const string arg0 = "arg0Value";
            const string arg1 = "arg1Value";

            LocatorException dependencyResolverException = new LocatorException(message, arg0, arg1);

            Assert.That(dependencyResolverException, Is.Not.Null);
            Assert.That(dependencyResolverException.Message, Is.EqualTo(expectedFormattedMessage));
        }

        [Category("UnitTest")]
        [Test]
        public void CanConstructWithMessageArg0Arg1AndArg2Parameters()
        {
            const string expectedFormattedMessage = "This is a formatted test message with arg0Value, arg1Value and arg2Value.";
            const string message = "This is a formatted test message with {0}, {1} and {2}.";
            const string arg0 = "arg0Value";
            const string arg1 = "arg1Value";
            const string arg2 = "arg2Value";

            LocatorException dependencyResolverException = new LocatorException(message, arg0, arg1, arg2);

            Assert.That(dependencyResolverException, Is.Not.Null);
            Assert.That(dependencyResolverException.Message, Is.EqualTo(expectedFormattedMessage));
        }

        [Category("UnitTest")]
        [Test]
        public void CanConstructWithMessageAndArgsParametersWithFourArgParamItems()
        {
            const string expectedFormattedMessage = "This is a formatted test message with arg0Value, arg1Value, arg2Value and arg3Value.";
            const string message = "This is a formatted test message with {0}, {1}, {2} and {3}.";
            const string arg0 = "arg0Value";
            const string arg1 = "arg1Value";
            const string arg2 = "arg2Value";
            const string arg3 = "arg3Value";

            LocatorException dependencyResolverException = new LocatorException(message, arg0, arg1, arg2, arg3);

            Assert.That(dependencyResolverException, Is.Not.Null);
            Assert.That(dependencyResolverException.Message, Is.EqualTo(expectedFormattedMessage));
        }

        [Category("UnitTest")]
        [Test]
        public void CanConstructWithMessageAndArgsParametersWithFourArgParamItemsAsArray()
        {
            const string expectedFormattedMessage = "This is a formatted test message with arg0Value, arg1Value, arg2Value and arg3Value.";
            const string message = "This is a formatted test message with {0}, {1}, {2} and {3}.";
            const string arg0 = "arg0Value";
            const string arg1 = "arg1Value";
            const string arg2 = "arg2Value";
            const string arg3 = "arg3Value";

            string[] args = new[] { arg0, arg1, arg2, arg3 };

            LocatorException dependencyResolverException = new LocatorException(message, args);

            Assert.That(dependencyResolverException, Is.Not.Null);
            Assert.That(dependencyResolverException.Message, Is.EqualTo(expectedFormattedMessage));
        }

        [Category("UnitTest")]
        [Test]
        public void CanConstructWithInnerExceptionAndMessageParameters()
        {
            const string message = "This is a test message.";

            Exception innerException = new Exception("This is an inner exception.");

            LocatorException dependencyResolverException = new LocatorException(innerException, message);

            Assert.That(dependencyResolverException, Is.Not.Null);
            Assert.That(dependencyResolverException.InnerException, Is.EqualTo(innerException));
            Assert.That(dependencyResolverException.Message, Is.EqualTo(message));
        }

        [Category("UnitTest")]
        [Test]
        public void CanConstructWithInnerExceptionMessageAndArg0Parameters()
        {
            const string expectedFormattedMessage = "This is a formatted test message with arg0Value.";
            const string message = "This is a formatted test message with {0}.";
            const string arg0 = "arg0Value";

            Exception innerException = new Exception("This is an inner exception.");

            LocatorException dependencyResolverException = new LocatorException(innerException, message, arg0);

            Assert.That(dependencyResolverException, Is.Not.Null);
            Assert.That(dependencyResolverException.InnerException, Is.EqualTo(innerException));
            Assert.That(dependencyResolverException.Message, Is.EqualTo(expectedFormattedMessage));
        }

        [Category("UnitTest")]
        [Test]
        public void CanConstructWithInnerExceptionMessageArg0AndArg1Parameters()
        {
            const string expectedFormattedMessage = "This is a formatted test message with arg0Value and arg1Value.";
            const string message = "This is a formatted test message with {0} and {1}.";
            const string arg0 = "arg0Value";
            const string arg1 = "arg1Value";

            Exception innerException = new Exception("This is an inner exception.");

            LocatorException dependencyResolverException = new LocatorException(innerException, message, arg0, arg1);

            Assert.That(dependencyResolverException, Is.Not.Null);
            Assert.That(dependencyResolverException.InnerException, Is.EqualTo(innerException));
            Assert.That(dependencyResolverException.Message, Is.EqualTo(expectedFormattedMessage));
        }

        [Category("UnitTest")]
        [Test]
        public void CanConstructWithInnerExceptionMessageArg0Arg1AndArg2Parameters()
        {
            const string expectedFormattedMessage = "This is a formatted test message with arg0Value, arg1Value and arg2Value.";
            const string message = "This is a formatted test message with {0}, {1} and {2}.";
            const string arg0 = "arg0Value";
            const string arg1 = "arg1Value";
            const string arg2 = "arg2Value";

            Exception innerException = new Exception("This is an inner exception.");

            LocatorException dependencyResolverException = new LocatorException(innerException, message, arg0, arg1, arg2);

            Assert.That(dependencyResolverException, Is.Not.Null);
            Assert.That(dependencyResolverException.InnerException, Is.EqualTo(innerException));
            Assert.That(dependencyResolverException.Message, Is.EqualTo(expectedFormattedMessage));
        }

        [Category("UnitTest")]
        [Test]
        public void CanConstructWithInnerExceptionMessageAndArgsParametersWithFourArgParamItems()
        {
            const string expectedFormattedMessage = "This is a formatted test message with arg0Value, arg1Value, arg2Value and arg3Value.";
            const string message = "This is a formatted test message with {0}, {1}, {2} and {3}.";
            const string arg0 = "arg0Value";
            const string arg1 = "arg1Value";
            const string arg2 = "arg2Value";
            const string arg3 = "arg3Value";

            Exception innerException = new Exception("This is an inner exception.");

            LocatorException dependencyResolverException = new LocatorException(innerException, message, arg0, arg1, arg2, arg3);

            Assert.That(dependencyResolverException, Is.Not.Null);
            Assert.That(dependencyResolverException.InnerException, Is.EqualTo(innerException));
            Assert.That(dependencyResolverException.Message, Is.EqualTo(expectedFormattedMessage));
        }

        [Category("UnitTest")]
        [Test]
        public void CanConstructWithInnerExceptionMessageAndArgsParametersWithFourArgParamItemsAsArray()
        {
            const string expectedFormattedMessage = "This is a formatted test message with arg0Value, arg1Value, arg2Value and arg3Value.";
            const string message = "This is a formatted test message with {0}, {1}, {2} and {3}.";
            const string arg0 = "arg0Value";
            const string arg1 = "arg1Value";
            const string arg2 = "arg2Value";
            const string arg3 = "arg3Value";

            string[] args = new[] { arg0, arg1, arg2, arg3 };

            Exception innerException = new Exception("This is an inner exception.");

            LocatorException dependencyResolverException = new LocatorException(innerException, message, args);

            Assert.That(dependencyResolverException, Is.Not.Null);
            Assert.That(dependencyResolverException.InnerException, Is.EqualTo(innerException));
            Assert.That(dependencyResolverException.Message, Is.EqualTo(expectedFormattedMessage));
        }

        [Category("UnitTest")]
        [Test]
        public void CanConstructUsingDeserializationConstructor()
        {
            const string expectedFormattedMessage = "This is a formatted test message with arg0Value, arg1Value, arg2Value and arg3Value.";
            const string expectedInnerExceptionMessage = "This is an inner exception.";
            const string message = "This is a formatted test message with {0}, {1}, {2} and {3}.";
            const string arg0 = "arg0Value";
            const string arg1 = "arg1Value";
            const string arg2 = "arg2Value";
            const string arg3 = "arg3Value";

            string[] args = new[] { arg0, arg1, arg2, arg3 };

            Exception innerException = new Exception(expectedInnerExceptionMessage);

            LocatorException dependencyResolverException1 = new LocatorException(innerException, message, args);

            // Serialize the dependency services exception into binary format.
            byte[] binaryData;
            using (MemoryStream memoryStream = new MemoryStream())
            {
                BinaryFormatter formatter = new BinaryFormatter();
                formatter.Serialize(memoryStream, dependencyResolverException1);

                binaryData = new byte[memoryStream.Length];
                memoryStream.Position = 0;
                memoryStream.Read(binaryData, 0, binaryData.Length);
                memoryStream.Close();
            }

            // Deserialize the binary data (serialized dependency services exception).
            LocatorException dependencyResolverException2;
            using (MemoryStream memoryStream = new MemoryStream(binaryData))
            {
                BinaryFormatter formatter = new BinaryFormatter();
                dependencyResolverException2 = (LocatorException)formatter.Deserialize(memoryStream);
            }

            Assert.That(dependencyResolverException2, Is.Not.Null);
            Assert.That(dependencyResolverException2.InnerException, Is.Not.Null);
            Assert.That(dependencyResolverException2.InnerException.Message, Is.EqualTo(expectedInnerExceptionMessage));
            Assert.That(dependencyResolverException2.Message, Is.EqualTo(expectedFormattedMessage));
        }
    }
}